
#include "Camera.h"


////////////////////////////////////////////////////////////////////////////////
/*----------------------------------------------------------------------------*/
Camera::Camera() {
	vEye  = Vec3f(1,0,0);
	vTarg = Vec3f(0,0,0);
	vUp   = Vec3f(0,0,1);
	fDist = 1;
	iPrevMouseX = -1;
	iPrevMouseY = -1;
	iTargAnimCurrFrame = 0;
}


////////////////////////////////////////////////////////////////////////////////
/*----------------------------------------------------------------------------*/
void Camera::update() {

	if ( iTargAnimCurrFrame ) { doTargAnimFrame(); }

	Vec3f eyePos = vTarg + (vEye*-fDist);

	gluLookAt(
		eyePos.x, eyePos.y, eyePos.z,
		vTarg.x,  vTarg.y,  vTarg.z,
		vUp.x,    vUp.y,    vUp.z
	);
}


////////////////////////////////////////////////////////////////////////////////
/*----------------------------------------------------------------------------*/
void Camera::startMouseRotation() {
	iPrevMouseX = -1;
	iPrevMouseY = -1;
}

/*----------------------------------------------------------------------------*/
void Camera::rotateWithMouse(int newX, int newY) {

	if ( iPrevMouseX == -1 && iPrevMouseY == -1 ) {
		iPrevMouseX = newX;
		iPrevMouseY = newY;
		return;
	}

	int moveX = newX-iPrevMouseX;
	int moveY = newY-iPrevMouseY;
	iPrevMouseX = newX;
	iPrevMouseY = newY;

	float rotX = moveX*-0.002f;
	float rotY = moveY*0.002f;

	Vec3f axisX = vUp;
	Vec3f axisY = vUp.crossedWith(vEye);

	Vec3f axis = axisX*rotX + axisY*rotY;
	axis.normalize();

	buildRotationMatrix( axis, (abs(rotX)+abs(rotY)) );
	vEye = rotateVector(vEye);
	vUp = rotateVector(vUp);
}

/*----------------------------------------------------------------------------*/
void Camera::rotateWithMouseTargeter(int newX, int newY, int oldX, int oldY) {

	int moveX = newX-oldX;
	int moveY = newY-oldY;

	float rotX = moveX*-0.02f;
	float rotY = moveY*0.02f;

	Vec3f axisX = vUp;
	Vec3f axisY = vUp.crossedWith(vEye);

	Vec3f axis = axisX*rotX + axisY*rotY;
	axis.normalize();

	buildRotationMatrix( axis, (abs(rotX)+abs(rotY)) );
	vEye = rotateVector(vEye);
	vUp = rotateVector(vUp);
}

/*----------------------------------------------------------------------------*/
void Camera::buildRotationMatrix(const Vec3f& axis, float a) {
	vRotTop.x = 1+(1-cos(a))*(axis.x*axis.x-1);
	vRotMid.y = 1+(1-cos(a))*(axis.y*axis.y-1);
	vRotBot.z = 1+(1-cos(a))*(axis.z*axis.z-1);

	vRotTop.y = -axis.z*sin(a)+(1-cos(a))*axis.x*axis.y;
	vRotMid.z = -axis.x*sin(a)+(1-cos(a))*axis.y*axis.z;
	vRotBot.x = -axis.y*sin(a)+(1-cos(a))*axis.x*axis.z;

	vRotTop.z =  axis.y*sin(a)+(1-cos(a))*axis.x*axis.z;
	vRotMid.x =  axis.z*sin(a)+(1-cos(a))*axis.x*axis.y;
	vRotBot.y =  axis.x*sin(a)+(1-cos(a))*axis.y*axis.z;
}

/*----------------------------------------------------------------------------*/
Vec3f Camera::rotateVector(const Vec3f& v) {
	Vec3f rotV;
	rotV.x = v*vRotTop;
	rotV.y = v*vRotMid;
	rotV.z = v*vRotBot;
	return rotV;
}


////////////////////////////////////////////////////////////////////////////////
/*----------------------------------------------------------------------------*/
void Camera::moveToNewTarget(Vec3f targ, const Vec3f* vel, int frames) {
	vTargNew = targ;
	vTargOrig = vTarg;
	vTargAnimEye = vel;
	iTargAnimFrames = frames;
	iTargAnimCurrFrame = frames;
}

/*----------------------------------------------------------------------------*/
void Camera::doTargAnimFrame() {
	iTargAnimCurrFrame--;

	if ( iTargAnimCurrFrame == 0 ) { 
		vTarg = vTargNew;
		vEye = (*vTargAnimEye);
		vEye.normalize();
		vTargAnimEye = NULL;
		return; 
	}

	float eyePercent = iTargAnimCurrFrame / (float)iTargAnimFrames;
	eyePercent *= eyePercent;

	vEye = (*vTargAnimEye)*(1-eyePercent) + vEye*eyePercent;
	vEye.normalize();

	eyePercent *= eyePercent;
	vTarg = vTargNew*(1-eyePercent) + vTargOrig*eyePercent;
}


////////////////////////////////////////////////////////////////////////////////
/*----------------------------------------------------------------------------*/
void Camera::setEyeVec(Vec3f& eye) { vEye = eye; }

/*----------------------------------------------------------------------------*/
void Camera::setTargetPos(Vec3f& target) { 
	if ( iTargAnimCurrFrame ) { vTargNew = target; }
	else { vTarg = target; }
}

/*----------------------------------------------------------------------------*/
void Camera::setUpVec(Vec3f& up) { vUp = up; }

/*----------------------------------------------------------------------------*/
void Camera::setZoomDist(float d) { fDist = d; }

/*----------------------------------------------------------------------------*/
float Camera::getZoomDist() { return fDist; }

/*----------------------------------------------------------------------------*/
Vec3f Camera::getUpVec() { return vUp; }

/*----------------------------------------------------------------------------*/
Vec3f Camera::getTargetPos() { return vTarg; }

/*----------------------------------------------------------------------------*/
void Camera::setZoomMinDist(float minDist) { fMinDist = minDist; }

/*----------------------------------------------------------------------------*/
void Camera::incZoomDist(float deltaZoom) { 
	fDist += deltaZoom;
	if ( fDist < fMinDist ) { fDist = fMinDist; }
}

/*----------------------------------------------------------------------------*/
Vec3f Camera::getEyePos() { return vEye*-fDist; }
